﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Globalization;

namespace JeanFish.Common
{
    /// <summary>
    /// 扩展时间方法。
    /// </summary>
    public static class DateTimeHelper
    {
        /// <summary>
        /// 无时区的ISO8601时间格式。
        /// </summary>
        public static string Iso8601Format = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.ffff";
        /// <summary>
        /// 带时区的ISO8601时间格式。
        /// </summary>
        public static string Iso8601TimeZoneFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.ffffzzzz";
        /// <summary>
        /// UTC时间的ISO8601时间格式。
        /// </summary>
        public static string Iso8601UtcFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.ffffZ";
        /// <summary>
        /// 将指定时间转换为ISO8601标准的字符串。
        /// 若时间为本地类型，转换为带时区的ISO8601时间格式；
        /// 若时间为UTC类型，转换为UTC时间的ISO8601时间格式；
        /// 若时间未指定类型，转换为无时区的ISO8601时间格式。
        /// </summary>
        /// <param name="dateTime">日期时间</param>
        /// <returns>ISO8601标准字符串</returns>
        public static string ToIso8601String(this DateTime dateTime)
        {
            switch (dateTime.Kind)
            {
                case DateTimeKind.Local:
                    return dateTime.ToString(Iso8601TimeZoneFormat);
                case DateTimeKind.Utc:
                    return dateTime.ToString(Iso8601UtcFormat);
                case DateTimeKind.Unspecified:
                default:
                    return dateTime.ToString(Iso8601Format);
            }
        }
        /// <summary>
        /// 将ISO8601标准的时间格式字符串转换为日期时间类型。
        /// 若输入无时区的ISO8601时间格式，转换为未指定类型的时间；
        /// 若输入UTC时间的ISO8601时间格式，转换为UTC类型的时间；
        /// 若指定类型为本地时间，转换为本地类型时间。
        /// </summary>
        /// <param name="iso8601">ISO8601标准格式的字符串</param>
        /// <param name="dateTime">当此方法返回时，如果转换成功，则包含ISO8601标准日期和时间等效的 System.DateTime 值；如果转换失败，则为 System.DateTime.MinValue。</param>
        /// <param name="kind">是否输出本地类型</param>
        /// <returns>转换是否成功</returns>
        public static bool TryParseIso8601(this string iso8601, out DateTime dateTime, DateTimeKind kind = DateTimeKind.Utc)
        {
            dateTime = DateTime.MinValue;
            bool result = DateTime.TryParseExact(iso8601,
                new string[] 
                {
                    Iso8601Format,
                    Iso8601TimeZoneFormat,
                    Iso8601UtcFormat
                },
                CultureInfo.InvariantCulture, 
                DateTimeStyles.AdjustToUniversal,
                out  dateTime);
            if (result && kind == DateTimeKind.Local)
                dateTime = dateTime.ToLocalTime();
            return result;
        }
    }
}
